/*
 * Copyright 2006 Abdulla G. Abdurakhmanov (abdulla.abdurakhmanov@gmail.com).
 * 
 * Licensed under the GPL, Version 2 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.gnu.org/copyleft/gpl.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * With any your questions welcome to my e-mail 
 * or blog at http://abdulla-a.blogspot.com.
 */

package org.ofsm.creator;

import java.awt.Color;
import java.util.List;
import java.util.Map;
import org.jgraph.JGraph;
import org.jgraph.graph.AttributeMap;
import org.jgraph.graph.DefaultEdge;
import org.jgraph.graph.DefaultGraphCell;
import org.jgraph.graph.DefaultGraphModel;
import org.ofsm.IState;
import org.ofsm.impl.FileFiniteStateMachineModel;
import org.ofsm.impl.StateTransition;

public class StateDiagramManager {
    private FileFiniteStateMachineModel model;
    private JGraph diagramGraph;

    public StateDiagramManager(FileFiniteStateMachineModel model, JGraph diagramGraph) {
        this.model = model;
        this.diagramGraph = diagramGraph;
    }

    public void setupModel() {            
        createGraphModel();        
    }
           
    private void createGraphModel() {
        diagramGraph.setModel(new DefaultGraphModel());        
        Map <IState,List < StateTransition> > transitions = model.getTransitionInfos();
        DiagramGraphCreationContext context = new DiagramGraphCreationContext();
        if(!model.getStateInfos().isEmpty()) {
            int x = 10, y = 50;
            for( FileFiniteStateMachineModel.StateInfo stateInfo : model.getStateInfos()) {
                createGraphCellGroup(stateInfo, context, x,y, null);
                y = context.getMaxUsedCoords().y + 50;
            }
            diagramGraph.getModel().insert(context.getGraphItems().toArray(), context.getAttributes(), context.getConnectionSet(), null, null);
            diagramGraph.getModel().addGraphModelListener(new StateGraphDiagramModelListener());
        }
    }

    private void createGraphCellGroup(FileFiniteStateMachineModel.StateInfo stateInfo, DiagramGraphCreationContext context, int currentX, int currentY, DefaultGraphCell stateCell) {
        if(context.getAlreadyCheckedStates().contains(stateInfo.getState()))
            return;
        else
            context.getAlreadyCheckedStates().add(stateInfo.getState());
        List<StateTransition> transitions = model.getTransitionInfo(stateInfo.getState());
        if(stateCell==null) {
            stateCell = createGraphCell(stateInfo, currentX, currentY, context);
            context.addCell(stateCell,stateInfo);
        }
        if(transitions == null) {
            return;
        }
        int idx = 0;
        for(StateTransition item: transitions) {
            //int x = currentX+200, y = currentY+ (idx*80);
            int x = currentX+200, y = context.getMaxUsedCoords().y+ (idx*80);
            DefaultGraphCell toStateCell =null;
            FileFiniteStateMachineModel.StateInfo toStateInfo =  model.getStateInfo(item.getToState().getName());
            if(item.getToState()!=stateInfo.getState()) {
                //toStateCell = context.getStateGraphLinks().get(item.getToState());
                toStateCell = null;
                if(toStateCell == null) {                    
                    toStateCell = createGraphCell(toStateInfo,x,y,context);
                    context.addCell(toStateCell,toStateInfo);
                    idx++;
                }
            }
            else
                toStateCell = stateCell;
            DefaultEdge edge = createEdge(stateCell, toStateCell, stateInfo, model.getEventInfo(item.getEvent().getName()),context);
            context.addEdge(stateCell, toStateCell,edge);
            createGraphCellGroup(toStateInfo,context,x,y,toStateCell);
        }
    }
    
    private DefaultGraphCell createGraphCell(FileFiniteStateMachineModel.StateInfo stateInfo, int x, int y, DiagramGraphCreationContext context) {
        if(context.getMaxUsedCoords().x < x)
            context.getMaxUsedCoords().x= x;
        if(context.getMaxUsedCoords().y < y)
            context.getMaxUsedCoords().y= y;
        DefaultGraphCell gm = new StateGraphCell(stateInfo);
        Color color = Color.blue;
        if(stateInfo.getState() == model.getInitialState())
            color = Color.red.darker();
        context.getAttributes().put(gm,
                        context.createBounds(new AttributeMap(), x, y, color));
        gm.addPort(null,stateInfo.getState().getName()+"/Center");
        return gm;
    }
    
    private DefaultEdge createEdge(DefaultGraphCell one, DefaultGraphCell two, FileFiniteStateMachineModel.StateInfo fromStateInfo, FileFiniteStateMachineModel.EventInfo eventInfo, DiagramGraphCreationContext context) {
        DefaultEdge result = new EventGraphEdge(eventInfo, fromStateInfo);
        context.getConnectionSet().connect(result, one.getChildAt(0), two.getChildAt(0));
        context.getAttributes().put(result, context.createArrowStyle(new AttributeMap(),Color.green.darker().darker(),true));
        return result;
    }

    public void removeSelectedTransition() {
        if(diagramGraph.getSelectionCount() == 1) {
            Object obj = diagramGraph.getSelectionCell();
            if(obj instanceof EventGraphEdge) {
                //((FileFiniteStateMachineModel.StateInfo)(((StateGraphCell)obj).getUserObject())).getState();
                model.deleteTransitionInfo(
                    ((EventGraphEdge)obj).getFromStateInfo().getState(), 
                    ((EventGraphEdge)obj).getEventInfo().getEvent()
                );
                 model.deleteEventInfo(((EventGraphEdge)obj).getEventInfo());
            }
        }    
    }
    
    public void setSelectedInitialState() {
        if(diagramGraph.getSelectionCount() == 1) {
            Object obj = diagramGraph.getSelectionCell();
            if(obj instanceof StateGraphCell) {
                model.setInitialState(((StateGraphCell)obj).getStateInfo().getState());
            }
        }
    }

    public void removeSelectedState(){
         if(diagramGraph.getSelectionCount() == 1) {
            Object obj = diagramGraph.getSelectionCell();
            if(obj instanceof StateGraphCell) {
                model.deleteStateInfo(((StateGraphCell)obj).getStateInfo());
            }
        }
    }
    
}
